// request.ts
import axios, {
  type AxiosRequestConfig,
  type AxiosResponse,
  type InternalAxiosRequestConfig,
  type AxiosError,
} from "axios";
import type { ApiResponse } from "../../types/api";
import apiDefaultConfig from "./config";
import { stringify } from "qs";

// -------------------------- 请求取消相关配置 --------------------------
// 创建取消令牌管理器：key = 请求唯一标识，value = AbortController
const cancelTokenSourceMap = new Map<string, AbortController>();
// 自动生成请求唯一标识key: 基于 url + method + params + data（避免同一接口不同参数被误取消）
function generateRequestKey(config: AxiosRequestConfig): string {
  const { url = "", method = "GET", params = {}, data = {} } = config;
  const serializedParams = stringify(params); // 序列化查询参数
  const serializedData = stringify(data); // 序列化请求体
  return `${url}-${method}-${serializedParams}-${serializedData}`;
}

// -------------------------- 创建axios实例 --------------------------
const requestInstance = axios.create({
  baseURL: apiDefaultConfig.base_url,
  timeout: apiDefaultConfig.request_timeout,
  // 自定义参数序列化函数
  paramsSerializer: (params) => {
    return stringify(params, { allowDots: true });
  },
});

// 白名单：无需携带Token的接口
const WHITE_LIST = ["/auth/login", "/auth/refresh-token"] as const;

// 全局变量：共享刷新Token的Promise（避免重复刷新）
let refreshPromise: Promise<string> | null = null;

// -------------------------- 请求拦截器：添加Token、注入取消信号 --------------------------
requestInstance.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // 1. 生成请求唯一标识
    const requestKey = generateRequestKey(config);
    // 2. 检查是否已存在取消信号
    const existingController = cancelTokenSourceMap.get(requestKey);
    if (existingController) {
      // 若存在，注入取消信号
      config.signal = existingController.signal;
    } else {
      // 若不存在，创建新的取消令牌
      const controller = new AbortController();
      cancelTokenSourceMap.set(requestKey, controller);
      config.signal = controller.signal;
    }

    if (typeof config.url !== "string") return config;

    // 3. 统一添加请求头
    if (WHITE_LIST.includes(config.url as (typeof WHITE_LIST)[number])) {
      return config;
    }
    // 添加token
    const token = localStorage.getItem("token");
    if (token && config.headers) {
      config.headers["Authorization"] = `Bearer ${token}`;
    }

    // 防止 GET 请求缓存
    if (config.method === "GET") {
      config.headers["Cache-Control"] = "no-cache";
      config.headers["Pragma"] = "no-cache";
    }
    // 自定义参数序列化函数
    else if (config.method === "POST") {
      const contentType = config.headers["Content-Type"] || config.headers["content-type"];
      if (contentType === "application/x-www-form-urlencoded") {
        if (config.data && typeof config.data !== "string") {
          config.data = stringify(config.data);
        }
      }
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// -------------------------- 核心函数：刷新Token --------------------------
async function refreshToken(): Promise<string> {
  const refreshToken = localStorage.getItem("refreshToken");
  if (!refreshToken) {
    throw new Error("No refresh token available");
  }
  try {
    const { token: newToken, "refresh-token": newRefreshToken } = (await requestInstance.post(
      "/auth/refresh-token",
      { "refresh-token": refreshToken },
      //  刷新请求超时设置
      { timeout: 10000 }
    )) as { token: string; "refresh-token": string };
    localStorage.setItem("token", newToken);
    localStorage.setItem("refreshToken", newRefreshToken);
    return newToken;
  } catch (error) {
    // 清理无效Token
    localStorage.removeItem("token");
    localStorage.removeItem("refreshToken");
    // 仅在浏览器环境跳转（避免SSR报错）
    if (typeof window !== "undefined") {
      window.location.replace("/login");
    }
    throw error;
  }
}

// -------------------------- 响应拦截器：超时重试、无感刷新token、清除取消控制器--------------------------
// 延迟函数，用于实现重试间隔
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// 响应拦截器
requestInstance.interceptors.response.use(
  (response: AxiosResponse): Promise<any> => {
    // 清理当前请求的控制器（请求成功）
    const requestKey = generateRequestKey(response.config);
    cancelTokenSourceMap.delete(requestKey);

    if (!response.data) {
      throw new Error("Response data is empty");
    }

    const apiRes = response.data as ApiResponse;
    if (apiRes.code !== apiDefaultConfig.result_code) {
      return Promise.reject({
        code: apiRes.code,
        message: apiRes.message || "Request failed (business error)",
        data: apiRes.data,
        isBusinessError: true,
      });
    }
    return apiRes.data;
  },
  async (error: AxiosError) => {
    console.log("error", error);
    
    // 1. 清理请求取消控制器（无论成功/失败/取消）
    if (error.config) {
      const requestKey = generateRequestKey(error.config);
      cancelTokenSourceMap.delete(requestKey);
    }
    // 2. 处理请求取消（单独处理，避免与其他错误混淆）
    if (axios.isCancel(error)) {
      console.log("Request canceled:", error.message);
      return Promise.reject({ ...error, isCanceled: true }); // 标记为取消错误
    }

    // _retryCount：已重试次数，_retry：标记是否已重试过
    const originalRequest = error.config as InternalAxiosRequestConfig;
    // 3. 处理401错误（未授权），优先于超时重试
    if (error.response && error.response.status === 401) {
      // 避免无限重试（已标记重试过）
      if ((originalRequest as InternalAxiosRequestConfig)._retry) {
        // 清理Token并跳转（无法刷新时）
        localStorage.removeItem("token");
        localStorage.removeItem("refreshToken");
        if (typeof window !== "undefined") {
          window.location.replace("/login");
        }
        return Promise.reject(error);
      }

      // 检查是否有refreshToken（必须存在才能刷新）
      if (!localStorage.getItem("refreshToken")) {
        localStorage.removeItem("token");
        localStorage.removeItem("refreshToken");
        if (typeof window !== "undefined") {
          window.location.replace("/login");
        }
        return Promise.reject(error);
      }

      // 标记请求已重试
      (originalRequest as InternalAxiosRequestConfig)._retry = true;

      try {
        // 共享刷新Promise避免重复刷新
        if (refreshPromise) {
          const newToken = await refreshPromise;
          if (originalRequest.headers) {
            originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
          }
          return requestInstance(originalRequest);
        }

        // 启动刷新流程
        refreshPromise = refreshToken();
        const newToken = await refreshPromise;

        if (originalRequest.headers) {
          originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
        }
        return requestInstance(originalRequest);
      } finally {
        refreshPromise = null;
      }
    }

    // 4. 超时重试（仅限ECONNABORTED错误）
    // 初始化重试计数
    if (!originalRequest._retryCount) {
      originalRequest._retryCount = 0;
    }
    if (
      error.code === "ECONNABORTED" &&
      originalRequest._retryCount < apiDefaultConfig.max_retry_count
    ) {
      // 增加重试计数
      originalRequest._retryCount++;

      // 计算指数退避延迟 (1s, 2s, 4s...)
      const delayTime = apiDefaultConfig.retry_delay * Math.pow(2, originalRequest._retryCount - 1);
      console.log(`请求超时，将在 ${delayTime}ms 后进行第 ${originalRequest._retryCount} 次重试`);
      // 等待延迟后重试
      await delay(delayTime);
      return requestInstance(originalRequest);
    }

    // 5. 其他错误直接拒绝
    return Promise.reject(error.response?.data);
  }
);

// -------------------------- 封装请求方法 --------------------------
const request = {
  get: async <T = any>(option: AxiosRequestConfig) => await requestInstance<T>({ method: "GET", ...option }) as unknown as T,
  post: async <T = any>(option: AxiosRequestConfig) => await requestInstance<T>({ method: "POST", ...option }) as unknown as T,
  put: async <T = any>(option: AxiosRequestConfig) =>  await requestInstance<T>({ method: "PUT", ...option }) as unknown as T,
  delete: async <T = any>(option: AxiosRequestConfig) => await requestInstance<T>({ method: "DELETE", ...option }) as unknown as T,
  download: async <T = Blob>(option: AxiosRequestConfig) => await requestInstance<T>({ ...option, responseType: "blob" as const }) as unknown as T,
  upload: async <T = any>(option: AxiosRequestConfig) => {
    return await requestInstance<T>({
      method: "POST",
      ...option,
      headers: {
        ...option.headers,
        "Content-Type": "multipart/form-data",
      },
    }) as unknown as T;
  },
  /**
   * 取消指定请求
   * @param config 请求配置对象, 必须包含method, url。params, data属性视请求类型而定，有必传
   */
  cancelRequest: (config: AxiosRequestConfig): void => {
    const requestKey = generateRequestKey(config);
    const controller = cancelTokenSourceMap.get(requestKey);
    if (controller) {
      controller.abort();
      cancelTokenSourceMap.delete(requestKey);
    }
  },
  // 取消所有请求
  cancelAllRequests: (): void => {
    for (const controller of cancelTokenSourceMap.values()) {
      controller.abort();
    }
    cancelTokenSourceMap.clear();
  },
};
// 监听页面卸载：重置refreshPromise
if (typeof window !== "undefined") {
  window.addEventListener("beforeunload", () => {
    refreshPromise = null;
    // 页面卸载时取消所有请求
    request.cancelAllRequests();
  });
}

export default request;
